package com.wms.catlog.aop;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;

import com.dianping.cat.Cat;
import com.dianping.cat.message.Event;
import com.dianping.cat.message.Message;
import com.dianping.cat.message.Transaction;
import com.dianping.cat.message.internal.AbstractMessage;
import com.wms.catlog.annotation.CatLogPoint;
import com.wms.catlog.annotation.EventType;
import com.wms.catlog.filter.PropertyContext;

public class CatLogPointAspect {

//	private static final Logger LOGGER = LoggerFactory.getLogger(WithCacheAspect.class);
	@Autowired
	protected HttpServletRequest request;


	public void doAround(ProceedingJoinPoint pjp) throws Throwable {
		Transaction transaction = null;
		String methodName = null;
		try {
			Method method = convMethod(pjp);
			CatLogPoint annotation = method.getAnnotation(CatLogPoint.class);
			if (annotation.enable()) {
				methodName = convMethodAllName(method);
				transaction = Cat.newTransaction(annotation.eventType().getValue(), methodName);
//				Cat.logEvent(annotation.eventType().getValue(), getIpAddress(request), Event.SUCCESS, method.getName());
				

				PropertyContext propertyContext = new PropertyContext();
				propertyContext.addProperty("_catRootMessageId", request.getHeader("X-CAT-ROOT-ID"));
				propertyContext.addProperty("_catParentMessageId", request.getHeader("X-CAT-PARENT-ID"));
				propertyContext.addProperty("_catChildMessageId", request.getHeader("X-CAT-CHILD-ID"));
				Cat.logRemoteCallServer(propertyContext);
				Cat.logEvent(EventType.SERVICE_METHOD.getValue(), request.getMethod(), Message.SUCCESS,
						request.getRequestURL().toString());
				Cat.logEvent(EventType.SERVICE_CLIENT.getValue(), request.getRemoteHost());
				String clientApp = request.getHeader("X-PPD-CAT-APP");
				Cat.logEvent(EventType.SERVICE_APP.getValue(), clientApp == null ? "unknown" : clientApp);
				
				
				transaction.setStatus(Transaction.SUCCESS);
			}
			pjp.proceed();

		} catch (Throwable t) {
			t.printStackTrace();
			Event event = Cat.newEvent("BIZ_ERROR", methodName);
			event.setStatus(t);
			completeEvent(event);
	
			transaction.addChild(event);
			transaction.setStatus(t.getClass().getSimpleName());
		} finally {
			transaction.complete();
		}

	}

	private Method convMethod(ProceedingJoinPoint pjp) throws NoSuchMethodException {
		MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
		Method interfaceMethod = methodSignature.getMethod();
		Method method = pjp.getTarget().getClass().getMethod(interfaceMethod.getName(),
				interfaceMethod.getParameterTypes());
		return method;
	}

	private String convMethodAllName(Method method) {
		return new StringBuffer().append(method.getDeclaringClass().getName()).append(".").append(method.getName())
				.toString();
	}

	private void completeEvent(Event event) {
		AbstractMessage message = (AbstractMessage) event;
		message.setCompleted(true);
	}

	/**
	 * 获取用户真实IP地址，不使用request.getRemoteAddr();的原因是有可能用户使用了代理软件方式避免真实IP地址,
	 * 
	 * 可是，如果通过了多级反向代理的话，X-Forwarded-For的值并不止一个，而是一串IP值，究竟哪个才是真正的用户端的真实IP呢？
	 * 答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。
	 * 
	 * 如：X-Forwarded-For：192.168.1.110, 192.168.1.120, 192.168.1.130, 192.168.1.100
	 * 
	 * 用户真实IP为： 192.168.1.110
	 * 
	 * @param request
	 * @return
	 */
	public static String getIpAddress(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}

}
